package com.zycfc.zsf.boot.util.time;

import java.util.*;

public abstract class ClockUtils
{
    private static Clock INSTANCE;
    
    public static synchronized DummyClock useDummyClock() {
        final DummyClock clock = new DummyClock();
        return (DummyClock)(ClockUtils.INSTANCE = clock);
    }
    
    public static synchronized DummyClock useDummyClock(final long timeStampMills) {
        final DummyClock clock = new DummyClock(timeStampMills);
        return (DummyClock)(ClockUtils.INSTANCE = clock);
    }
    
    public static synchronized DummyClock useDummyClock(final Date date) {
        final DummyClock clock = new DummyClock(date);
        return (DummyClock)(ClockUtils.INSTANCE = clock);
    }
    
    public static synchronized void useDefaultClock() {
        ClockUtils.INSTANCE = new DefaultClock();
    }
    
    public static Date currentDate() {
        return ClockUtils.INSTANCE.currentDate();
    }
    
    public static long currentTimeMillis() {
        return ClockUtils.INSTANCE.currentTimeMillis();
    }
    
    public static long nanoTime() {
        return ClockUtils.INSTANCE.nanoTime();
    }
    
    static {
        ClockUtils.INSTANCE = new DefaultClock();
    }
    
    public static class DefaultClock implements Clock
    {
        @Override
        public Date currentDate() {
            return new Date();
        }
        
        @Override
        public long currentTimeMillis() {
            return System.currentTimeMillis();
        }
        
        @Override
        public long nanoTime() {
            return System.nanoTime();
        }
    }
    
    public static class DummyClock implements Clock
    {
        private long time;
        private long nanoTme;
        
        public DummyClock() {
            this(System.currentTimeMillis());
        }
        
        public DummyClock(final Date date) {
            this(date.getTime());
        }
        
        public DummyClock(final long time) {
            this.time = time;
            this.nanoTme = System.nanoTime();
        }
        
        @Override
        public Date currentDate() {
            return new Date(this.time);
        }
        
        @Override
        public long currentTimeMillis() {
            return this.time;
        }
        
        @Override
        public long nanoTime() {
            return this.nanoTme;
        }
        
        public void updateNow(final Date newDate) {
            this.time = newDate.getTime();
        }
        
        public void updateNow(final long newTime) {
            this.time = newTime;
        }
        
        public void increaseTime(final int millis) {
            this.time += millis;
        }
        
        public void decreaseTime(final int millis) {
            this.time -= millis;
        }
        
        public void setNanoTime(final long nanoTime) {
            this.nanoTme = nanoTime;
        }
    }
    
    public interface Clock
    {
        Date currentDate();
        
        long currentTimeMillis();
        
        long nanoTime();
    }
}
